#ifndef SHAPE_H
#define SHAPE_H

#include <QPoint>
#include <QColor>
#include <QPen>
#include <QPainter>
#include <QPainterPath>
#include <QImage>
#include <QRect>
#include <vector>
#include <string>
#include <map>
#include <opencv2/opencv.hpp>


class Shape
{
public:
	// Constants
	static const int P_SQUARE; // Render handles as squares
	static const int P_ROUND; // Render handles as circles

	static const int MOVE_VERTEX; // Flag for the handles we would move if dragging
	static const int NEAR_VERTEX; // Flag for all other handles on the current shape

	static const int PEN_WIDTH;

	// The following class variables influence the drawing of all shape objects.
	static QColor line_color;
	static QColor fill_color;
	static QColor select_line_color;
	static QColor select_fill_color;
	static QColor vertex_fill_color;
	static QColor hvertex_fill_color;
	static int point_type;
	static int point_size;
	static double scale;

	// Constructor
	Shape(
		const QString& label = "",
		const QColor& line_color = QColor(),
		const QString& shape_type = "",
		const std::map<QString, QString>& flags = {},
		int group_id = -1,
		const QString& description = "",
		const cv::Mat& mask = cv::Mat()
	);

	// Methods
	void setShapeRefined(
		const QString& shape_type,
		const QList<QPointF>& points,
		const QList<int>& point_labels,
		const cv::Mat& mask = cv::Mat()
	);

	void restoreShapeRaw();

	void close();

	void addPoint(const QPointF& point, int label = 1);

	bool canAddPoint() const;

	QPointF popPoint();

	void insertPoint(int i, const QPointF& point, int label = 1);

	void removePoint(int i);

	bool isClosed() const;

	void setOpen();

	void paint(QPainter* painter);

	void drawVertex(QPainterPath& path, int i);

	int nearestVertex(const QPointF& point, double epsilon) const;

	int nearestEdge(const QPointF& point, double epsilon) const;

	bool containsPoint(const QPointF& point) const;

	QPainterPath makePath() const;

	QRectF boundingRect() const;

	void moveBy(const QPointF& offset);

	void moveVertexBy(int i, const QPointF& offset);

	void highlightVertex(int i, int action);

	void highlightClear();

	Shape* copy() const;

	int size() const;

	QPointF operator[](int key) const;

	void setPoint(int key, const QPointF& value);

	// Getters and setters for shape_type
	const QString& getShapeType() const;

	void setShapeType(const QString& value);

	QString label;
	bool selected;
	bool fill;
	QString shape_type;
	QList<QPointF> points;
	QList<int> point_labels;
	std::map<QString, QString> flags;
	int group_id;
	QString description;

private:
	// Member variables

	std::tuple<QString, QList<QPointF>, QList<int>> _shape_raw;
	
	std::map<QString, QString> other_data;
	cv::Mat mask;

	int _highlightIndex;
	int _highlightMode;
	std::map<int, std::pair<double, int>> _highlightSettings;

	bool _closed;
	QColor _vertex_fill_color;

	// Helper methods
	QPointF _scale_point(const QPointF& point) const;

	bool isValidShapeType(const QString& value) const;
};

Q_DECLARE_METATYPE(Shape)

#endif // SHAPE_H
